
/*
* Copyright (c) Z.G. Shi  <blueflycn at gmail dot com>
* Make a better world~
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <ctype.h>

#include "tyan.h"
#include "tyn_utils.h"
#include "qsort.h"


int tyn_write(int fd, char *buffer, size_t buffer_size) {
    size_t chunk_size = 1*1024*1024;
    char *p = buffer;
    size_t total_written = 0;
    while(buffer_size > 0) {
        size_t size_to_write = buffer_size > chunk_size ? chunk_size : buffer_size;
        int size_written = write(fd, p, size_to_write);
        
        p += size_written;
        buffer_size -= size_written;
        total_written += size_written;
    }
    return total_written;
}

int tyn_read(int fd, char *buffer, size_t buffer_size) {
    size_t chunk_size = 1*1024*1024;
    char *p = buffer;
    size_t total_read = 0;
    while(buffer_size > 0) {
        size_t size_to_read = buffer_size > chunk_size ? chunk_size : buffer_size;
        int size_read = read(fd, p, size_to_read);
        if(size_read == 0) {
            break;
        }
        if(size_read == -1) {
            tyn_log(stderr, "error in read");
            return TYN_ERROR;
        }
        p += size_read;
        buffer_size -= size_read;
        total_read += size_read;
    }
    return total_read;
}
//------------------------------------------------------------------------------
int tyn_compare_float(float *a, float *b) {
    //return (*a > *b) - (*a < *b);
    return (*a > *b) - (*a < *b);
}
int tyn_compare_uint32_t(uint32_t *a, uint32_t *b) {
    return (*a > *b) - (*a < *b);
}

int tyn_compare_string_by_hash32(char **a, char **b) {
    uint32_t hash_a = tyn_hash32(*a, strlen(*a));
    uint32_t hash_b = tyn_hash32(*b, strlen(*b));
    return (hash_a > hash_b) - (hash_a < hash_b);
}

int tyn_bget_array_idx_uint32_t(uint32_t element, uint32_t *array, size_t array_size) {
    //bsearch (const void *key, const void *array, size_t count, size_t size, comparison_fn_t compare)
    uint32_t *p = bsearch(&element, array, array_size, sizeof(uint32_t), tyn_compare_uint32_t);
    if(p != NULL) {
        return p - array;
    }
    return -1;
}

int tyn_lget_array_idx_uint32_t(uint32_t element, uint32_t *array, size_t array_size) {
    for(int i = 0; i < array_size; i++) {               
        if(*(array + i) == element) {                   
            return i;                                   
        }                                               
    }                                                   
    return -1;
    
}
//-------------------------------------------------------------------------------
int32_t tyn_strntoi(char *str, size_t str_len) {
  int32_t sign = 1;
  int32_t value = 0;

  for(; str_len > 0 && *str == '-'; str++, str_len--) {
    sign *= -1;
  }

  for(; str_len > 0 && isdigit(*str); str++, str_len--) {
   value *= 10;
   value += *str - '0';
  }
  value *= sign;
  //printf("convert:%lld\n", value);
  return value;
}

uint32_t tyn_strntoui(char *str, size_t str_len) {
  uint32_t value = 0;

  for(; str_len > 0 && isdigit(*str); str++, str_len--) {
   value *= 10;
   value += *str - '0';
  }
  return value;
}


int64_t tyn_strntol(char *str, size_t str_len) {
  int64_t sign = 1;
  int64_t value = 0;

  for(; str_len > 0 && *str == '-'; str++, str_len--) {
    sign *= -1;
  }

  for(; str_len > 0 && isdigit(*str); str++, str_len--) {
   value *= 10;
   value += *str - '0';
  }
  value *= sign;
  //printf("convert:%lld\n", value);
  return value;
}

uint64_t tyn_strntoul(char *str, size_t str_len) {
  uint64_t value = 0;

  for(; str_len > 0 && isdigit(*str); str++, str_len--) {
   value *= 10;
   value += *str - '0';
  }
  return value;
}


float tyn_strntof(char *str, size_t str_len) {
    return atof(str);
}

double tyn_strntod(char *str, size_t str_len) {
    return strtod(str, NULL);
}
//---------------------------------------------
unsigned int tyn_fnv_hash32(char* str, unsigned int len)
{
   //this is fnv32 hash
   const unsigned int fnv_prime = 0x811C9DC5;
   unsigned int hash      = 0;
   unsigned int i         = 0;

   for(i = 0; i < len; str++, i++)
   {
      hash *= fnv_prime;
      hash ^= (*str);
   }

   return hash;
}

int tyn_log(FILE *stream, char *format, ...) {
    va_list args;
    va_start (args, format);
    vfprintf (stream, format, args);
    fprintf(stream, "\n");
    va_end (args);
}

//-----------------------------------------------------------------------------

uint32_t tyn_hash32 ( const void * key, int len)
{
  const uint8_t * data = (const uint8_t*)key;
  const int nblocks = len / 4;

  uint32_t h1 = 19831024;//h1 initialized from seed

  uint32_t c1 = 0xcc9e2d51;
  uint32_t c2 = 0x1b873593;

  //----------
  // body

  const uint32_t * blocks = (const uint32_t *)(data + nblocks*4);

  for(int i = -nblocks; i; i++)
  {
    //uint32_t k1 = getblock(blocks,i);
    uint32_t k1 = blocks[i];
    k1 *= c1;
    k1 = (k1 << 15) | (k1 >> 17);//rotl32(k1,15);
    k1 *= c2;
    
    h1 ^= k1;
    h1 = (h1 << 13) | (h1 >> 19);//rotl32(h1,13); 
    h1 = h1*5+0xe6546b64;
  }

  //----------
  // tail

  const uint8_t * tail = (const uint8_t*)(data + nblocks*4);

  uint32_t k1 = 0;

  switch(len & 3)
  {
  case 3: k1 ^= tail[2] << 16;
  case 2: k1 ^= tail[1] << 8;
  case 1: k1 ^= tail[0];
          k1 *= c1; k1 = (k1 << 15) | (k1 >> 17); k1 *= c2; h1 ^= k1;
  };

  //----------
  // finalization

  h1 ^= len;
  //h1 = fmix(h1);
  h1 ^= h1 >> 16;
  h1 *= 0x85ebca6b;
  h1 ^= h1 >> 13;
  h1 *= 0xc2b2ae35;
  h1 ^= h1 >> 16;
  return h1;
  //*(uint32_t*)out = h1;
} 

//-----------------------------------------------------------------------------